/**
 * 音频处理工具类
 * 包含录音、格式转换、音频分析等功能
 */

// 音频录制配置
export interface AudioRecordConfig {
  sampleRate?: number; // 采样率，默认16000
  channels?: number;   // 声道数，默认1（单声道）
  bufferSize?: number; // 缓冲区大小，默认4096
}

// 音频录制事件回调
export interface AudioRecordEvents {
  onDataAvailable?: (audioData: ArrayBuffer) => void;
  onError?: (error: string) => void;
  onVolumeChange?: (volume: number) => void;
}

/**
 * 音频录制管理器
 */
export class AudioRecorder {
  private mediaRecorder: MediaRecorder | null = null;
  private audioContext: AudioContext | null = null;
  private analyser: AnalyserNode | null = null;
  private microphone: MediaStreamAudioSourceNode | null = null;
  private processor: ScriptProcessorNode | null = null;
  private volumeMonitorId: number | null = null;
  private stream: MediaStream | null = null;
  private isRecording: boolean = false;

  private config: Required<AudioRecordConfig>;
  private events: AudioRecordEvents;

  constructor(config: AudioRecordConfig = {}, events: AudioRecordEvents = {}) {
    this.config = {
      sampleRate: 16000,
      channels: 1,
      bufferSize: 4096,
      ...config
    };
    this.events = events;
  }

  /**
   * 检查浏览器是否支持音频录制
   */
  static isSupported(): boolean {
    return !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia);
  }

  /**
   * 请求麦克风权限并初始化录音
   */
  async initialize(): Promise<void> {
    try {
      if (!AudioRecorder.isSupported()) {
        throw new Error('当前浏览器不支持音频录制功能');
      }

      // 请求麦克风权限
      this.stream = await navigator.mediaDevices.getUserMedia({
        audio: {
          sampleRate: this.config.sampleRate,
          channelCount: this.config.channels,
          echoCancellation: true,
          noiseSuppression: true,
          autoGainControl: true
        }
      });

      // 创建音频上下文
      this.audioContext = new (window.AudioContext || (window as any).webkitAudioContext)({
        sampleRate: this.config.sampleRate
      });

      // 创建分析器用于音量检测
      this.analyser = this.audioContext.createAnalyser();
      this.analyser.fftSize = 512;
      this.analyser.smoothingTimeConstant = 0.8;

      // 连接麦克风到分析器
      this.microphone = this.audioContext.createMediaStreamSource(this.stream);
      this.microphone.connect(this.analyser);

      // 创建音频处理器用于获取PCM数据
      this.processor = this.audioContext.createScriptProcessor(1024, 1, 1);
      this.processor.onaudioprocess = (event) => {
        if (this.isRecording) {
          const inputData = event.inputBuffer.getChannelData(0);

          // 转换为16位PCM
          const pcmData = new Int16Array(inputData.length);
          for (let i = 0; i < inputData.length; i++) {
            const sample = Math.max(-1, Math.min(1, inputData[i]));
            pcmData[i] = sample < 0 ? sample * 0x8000 : sample * 0x7FFF;
          }

          // 发送PCM数据
          this.events.onDataAvailable?.(pcmData.buffer);
        }
      };

      // 连接音频处理链
      this.microphone.connect(this.processor);
      this.processor.connect(this.audioContext.destination);

      // 创建MediaRecorder（备用）
      this.mediaRecorder = new MediaRecorder(this.stream, {
        mimeType: this.getSupportedMimeType()
      });

      this.setupMediaRecorderEvents();

      // console.log('🎤 音频录制器初始化成功');
    } catch (error) {
      // console.error('🎤 音频录制器初始化失败:', error);
      console.error('audio recorder initialization failed', error);
      // this.events.onError?.(`初始化失败: ${error instanceof Error ? error.message : '未知错误'}`);
      this.events.onError?.(`initialization failed: ${error instanceof Error ? error.message : 'unknown error'}`);
      throw error;
    }
  }

  /**
   * 开始录音
   */
  async startRecording(): Promise<void> {
    if (!this.audioContext || !this.processor) {
      await this.initialize();
    }

    if (!this.isRecording) {
      this.isRecording = true;
      this.startVolumeMonitoring();
      // console.log('🎤 开始录音（PCM格式，适用于腾讯云）');
    }
  }

  /**
   * 停止录音
   */
  stopRecording(): void {
    if (this.isRecording) {
      this.isRecording = false;
      this.stopVolumeMonitoring();
      // console.log('🎤 停止录音');
    }
  }

  /**
   * 销毁录音器，释放资源
   */
  destroy(): void {
    this.stopRecording();
    this.stopVolumeMonitoring();

    // 断开音频节点连接
    if (this.processor) {
      this.processor.disconnect();
      this.processor = null;
    }

    if (this.microphone) {
      this.microphone.disconnect();
      this.microphone = null;
    }

    if (this.analyser) {
      this.analyser.disconnect();
      this.analyser = null;
    }

    if (this.stream) {
      this.stream.getTracks().forEach(track => track.stop());
      this.stream = null;
    }

    if (this.audioContext?.state !== 'closed') {
      this.audioContext?.close();
      this.audioContext = null;
    }

    this.mediaRecorder = null;
    this.isRecording = false;

    // console.log('🎤 音频录制器已销毁');
  }

  /**
   * 获取当前音量（0-100）
   */
  getCurrentVolume(): number {
    if (!this.analyser) return 0;

    const bufferLength = this.analyser.frequencyBinCount;
    const dataArray = new Uint8Array(bufferLength);
    this.analyser.getByteFrequencyData(dataArray);

    let sum = 0;
    for (let i = 0; i < bufferLength; i++) {
      sum += dataArray[i];
    }

    const average = sum / bufferLength;
    return Math.round((average / 255) * 100);
  }

  /**
   * 设置MediaRecorder事件处理
   */
  private setupMediaRecorderEvents(): void {
    if (!this.mediaRecorder) return;

    this.mediaRecorder.ondataavailable = (event) => {
      if (event.data.size > 0) {
        // 将Blob转换为ArrayBuffer
        event.data.arrayBuffer().then((buffer) => {
          this.events.onDataAvailable?.(buffer);
        }).catch((error) => {
          // console.error('🎤 音频数据转换失败:', error);
          console.error('audio data conversion failed', error);
          // this.events.onError?.('音频数据处理失败');
          this.events.onError?.('audio data processing failed');
        });
      }
    };

    this.mediaRecorder.onerror = (event) => {
      // console.error('🎤 MediaRecorder错误:', event);
      console.error('MediaRecorder error', event);
      // this.events.onError?.('录音过程中发生错误');
      this.events.onError?.('error occurred during recording');
    };
  }

  /**
   * 开始音量监控
   */
  private startVolumeMonitoring(): void {
    if (this.volumeMonitorId) return;

    this.volumeMonitorId = window.setInterval(() => {
      const volume = this.getCurrentVolume();
      this.events.onVolumeChange?.(volume);
    }, 100);
  }

  /**
   * 停止音量监控
   */
  private stopVolumeMonitoring(): void {
    if (this.volumeMonitorId) {
      clearInterval(this.volumeMonitorId);
      this.volumeMonitorId = null;
    }
  }

  /**
   * 获取支持的MIME类型
   */
  private getSupportedMimeType(): string {
    const types = [
      'audio/webm;codecs=opus',
      'audio/webm',
      'audio/mp4',
      'audio/ogg;codecs=opus'
    ];

    for (const type of types) {
      if (MediaRecorder.isTypeSupported(type)) {
        return type;
      }
    }

    return 'audio/webm'; // 默认回退
  }
}

/**
 * PCM格式转换工具
 */
export class PCMConverter {
  /**
   * 将音频Buffer转换为PCM格式
   */
  static async audioBufferToPCM(audioBuffer: AudioBuffer): Promise<ArrayBuffer> {
    const length = audioBuffer.length;
    const channels = audioBuffer.numberOfChannels;
    // const sampleRate = audioBuffer.sampleRate;

    // 如果是立体声，混合为单声道
    const pcmData = new Float32Array(length);

    if (channels === 1) {
      pcmData.set(audioBuffer.getChannelData(0));
    } else {
      const leftChannel = audioBuffer.getChannelData(0);
      const rightChannel = audioBuffer.getChannelData(1);

      for (let i = 0; i < length; i++) {
        pcmData[i] = (leftChannel[i] + rightChannel[i]) / 2;
      }
    }

    // 转换为16位PCM
    const pcm16 = new Int16Array(length);
    for (let i = 0; i < length; i++) {
      const sample = Math.max(-1, Math.min(1, pcmData[i]));
      pcm16[i] = sample < 0 ? sample * 0x8000 : sample * 0x7FFF;
    }

    return pcm16.buffer;
  }

  /**
   * 重采样音频数据
   */
  static resample(audioData: Float32Array, originalSampleRate: number, targetSampleRate: number): Float32Array {
    if (originalSampleRate === targetSampleRate) {
      return audioData;
    }

    const ratio = originalSampleRate / targetSampleRate;
    const newLength = Math.round(audioData.length / ratio);
    const result = new Float32Array(newLength);

    for (let i = 0; i < newLength; i++) {
      const index = i * ratio;
      const indexInt = Math.floor(index);
      const indexFrac = index - indexInt;

      if (indexInt < audioData.length - 1) {
        result[i] = audioData[indexInt] * (1 - indexFrac) + audioData[indexInt + 1] * indexFrac;
      } else {
        result[i] = audioData[indexInt] || 0;
      }
    }

    return result;
  }
}

/**
 * 音频格式检测和兼容性检查
 */
export class AudioCompatibility {
  /**
   * 检查浏览器对各种音频功能的支持
   */
  static checkSupport() {
    return {
      getUserMedia: !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia),
      mediaRecorder: typeof MediaRecorder !== 'undefined',
      audioContext: !!(window.AudioContext || (window as any).webkitAudioContext),
      webAudio: typeof AudioContext !== 'undefined',
      webSocket: typeof WebSocket !== 'undefined'
    };
  }

  /**
   * 获取支持的音频格式
   */
  static getSupportedAudioFormats(): string[] {
    const formats = [
      'audio/webm;codecs=opus',
      'audio/webm',
      'audio/mp4',
      'audio/ogg;codecs=opus',
      'audio/wav'
    ];

    return formats.filter(format => MediaRecorder.isTypeSupported(format));
  }

  /**
   * 检查设备是否为移动设备
   */
  static isMobileDevice(): boolean {
    return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
  }

  /**
   * 检测可用的音频输入设备
   */
  static async getAudioInputDevices(): Promise<MediaDeviceInfo[]> {
    try {
      if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) {
        console.warn('🎤 设备枚举API不可用');
        return [];
      }

      const devices = await navigator.mediaDevices.enumerateDevices();
      const audioInputs = devices.filter(device => device.kind === 'audioinput');

      // console.log('🎤 检测到的音频输入设备:', audioInputs);
      return audioInputs;
    } catch (error) {
      // console.error('🎤 获取音频设备失败:', error);
      console.error('get audio device failed', error);
      return [];
    }
  }

  /**
   * 测试麦克风权限和可用性
   */
  static async testMicrophoneAccess(): Promise<{
    hasPermission: boolean;
    hasDevices: boolean;
    error?: string;
    devices?: MediaDeviceInfo[];
  }> {
    try {
      // console.log('🎤 开始测试麦克风访问权限...');

      // 1. 检查是否有音频输入设备
      const devices = await this.getAudioInputDevices();
      const hasDevices = devices.length > 0;

      if (!hasDevices) {
        console.warn('🎤 未检测到音频输入设备');
        return {
          hasPermission: false,
          hasDevices: false,
          error: 'noMicrophoneDetected',
          devices
        };
      }

      // 2. 尝试请求麦克风权限
      try {
        const stream = await navigator.mediaDevices.getUserMedia({
          audio: {
            sampleRate: 16000,
            channelCount: 1,
            echoCancellation: true,
            noiseSuppression: true,
            autoGainControl: true
          }
        });

        // console.log('🎤 麦克风权限获取成功');

        // 立即停止流以释放资源
        stream.getTracks().forEach(track => track.stop());

        return {
          hasPermission: true,
          hasDevices: true,
          devices
        };
      } catch (permissionError) {
        // console.error('🎤 麦克风权限被拒绝:', permissionError);
        console.error('microphone permission denied', permissionError);

        let errorMsg = '麦克风权限被拒绝';
        if (permissionError instanceof Error) {
          if (permissionError.name === 'NotAllowedError') {
            // errorMsg = '用户拒绝了麦克风权限，请在浏览器设置中允许麦克风访问';
            errorMsg = 'user denied microphone permission, please allow microphone access in browser settings';
          } else if (permissionError.name === 'NotFoundError') {
            // errorMsg = '未找到可用的麦克风设备';
            errorMsg = 'no available microphone device found';
          } else if (permissionError.name === 'NotReadableError') {
            // errorMsg = '麦克风设备被其他应用占用';
            errorMsg = 'microphone device is occupied by other applications';
          } else {
            // errorMsg = `麦克风访问失败: ${permissionError.message}`;
            errorMsg = `microphone access failed: ${permissionError.message}`;
          }
        }

        return {
          hasPermission: false,
          hasDevices: true,
          error: errorMsg,
          devices
        };
      }
    } catch (error) {
      // console.error('🎤 麦克风测试失败:', error);
      console.error('microphone test failed', error);
      return {
        hasPermission: false,
        hasDevices: false,
        // error: `麦克风测试失败: ${error instanceof Error ? error.message : '未知错误'}`
        error: `microphone test failed: ${error instanceof Error ? error.message : 'unknown error'}`
      };
    }
  }

  /**
   * 获取浏览器信息
   */
  static getBrowserInfo(): {
    name: string;
    version: string;
    isMobile: boolean;
    supportsWebRTC: boolean;
  } {
    const userAgent = navigator.userAgent;
    let name = 'Unknown';
    let version = 'Unknown';

    if (userAgent.includes('Chrome')) {
      name = 'Chrome';
      const match = userAgent.match(/Chrome\/(\d+)/);
      version = match ? match[1] : 'Unknown';
    } else if (userAgent.includes('Firefox')) {
      name = 'Firefox';
      const match = userAgent.match(/Firefox\/(\d+)/);
      version = match ? match[1] : 'Unknown';
    } else if (userAgent.includes('Safari') && !userAgent.includes('Chrome')) {
      name = 'Safari';
      const match = userAgent.match(/Version\/(\d+)/);
      version = match ? match[1] : 'Unknown';
    } else if (userAgent.includes('Edge')) {
      name = 'Edge';
      const match = userAgent.match(/Edge\/(\d+)/);
      version = match ? match[1] : 'Unknown';
    }

    return {
      name,
      version,
      isMobile: this.isMobileDevice(),
      supportsWebRTC: !!(navigator.mediaDevices && window.RTCPeerConnection)
    };
  }

  /**
   * 完整的兼容性诊断
   */
  static async performDiagnostics(): Promise<{
    browser: ReturnType<typeof AudioCompatibility.getBrowserInfo>;
    support: ReturnType<typeof AudioCompatibility.checkSupport>;
    microphone: Awaited<ReturnType<typeof AudioCompatibility.testMicrophoneAccess>>;
    formats: string[];
    recommendations: string[];
  }> {
    // console.log('🔍 开始音频兼容性诊断...');

    const browser = this.getBrowserInfo();
    const support = this.checkSupport();
    const microphone = await this.testMicrophoneAccess();
    const formats = this.getSupportedAudioFormats();

    const recommendations: string[] = [];

    // 生成建议
    if (!support.getUserMedia) {
      recommendations.push('请使用现代浏览器（Chrome 56+、Firefox 56+、Safari 11+）');
    }
    if (!support.webSocket) {
      recommendations.push('请升级浏览器以支持WebSocket');
    }
    if (!microphone.hasDevices) {
      recommendations.push('请连接麦克风设备');
    }
    if (!microphone.hasPermission) {
      recommendations.push('请允许浏览器访问麦克风权限');
    }
    if (formats.length === 0) {
      recommendations.push('当前浏览器不支持音频录制格式');
    }

    const result = {
      browser,
      support,
      microphone,
      formats,
      recommendations
    };

    // console.log('🔍 音频兼容性诊断结果:', result);
    return result;
  }
} 